package it.polito.connectedcar.network;

import it.polito.connectedcar.util.LatLng;

import java.net.InetAddress;
import java.net.UnknownHostException;

import de.uniluebeck.itm.tcpip.Storage;

public class VehicleMessage extends Message{

	
	private Float speed;
	private LatLng position;
	private VehicleMessageCode vehicleMessageCode;
	private InetAddress address;
	private Integer port;
	private boolean newVehicle=false;
	private boolean removeVehicle = false;
	public VehicleMessage() {
		super(EntityType.VEHICLE);
	}
	public VehicleMessage(byte[] data)
	{
		super(EntityType.VEHICLE,data);
	}
		
	public void putSpeed(float speed)
	{
		this.speed= speed;
	}
	
	public void putPosition(LatLng latLng)
	{
		this.position= latLng;
	}
	
	public VehicleMessageCode getMessageCode()
	{
		return vehicleMessageCode;
	}
	
	public void putMessageCode(VehicleMessageCode messageCode)
	{
		this.vehicleMessageCode = messageCode;
	}
	
	protected void convertToData(Storage st)
	{
		
		st.writeByte(vehicleMessageCode.code);
		if(speed!=null)
		{
			st.writeByte(VehicleAttribute.SPEED.getCode());
			st.writeFloat(speed);
		}
		if(position!=null)
		{
			st.writeByte(VehicleAttribute.POSITION.getCode());
			st.writeDouble(position.getlatitude());
			st.writeDouble(position.getLongitude());
		}
	}

	@Override
	protected void convertFromData(Storage st) {
		this.vehicleMessageCode = VehicleMessageCode.fromCode(st.readByte());
		
		int expectedMaxAttrCount = 2;
		int counter = 0;
		while(st.validPos() && counter<expectedMaxAttrCount)
		{
			extractAttributes(st);
			counter++;
		}
		
	}
	private void extractAttributes(Storage st) {
		int attributeCode = st.readByte();
		VehicleAttribute attribute = VehicleAttribute.fromCode(attributeCode);
		switch(attribute)
		{
			case POSITION:
				double latitude = st.readDouble();
				double longitude = st.readDouble();
				position = new LatLng(latitude, longitude);
			break;
			case SPEED:
				speed = st.readFloat();
				break;
			case ADD_VEHICLE_ADDRESS:
				try {
					address = InetAddress.getByName(st.readStringASCII());
					this.port = st.readInt();
					setNewVehicle(true);
				} catch (UnknownHostException e) {
					e.printStackTrace();
				} 
			break;
			case REMOVE_VEHICLE_ADDRESS:
				try {
					address = InetAddress.getByName(st.readStringASCII());
					this.port = st.readInt();
					removeVehicle=true;
				} catch (UnknownHostException e) {
					e.printStackTrace();
				}				
			default:
				
			break;
		}
	}
	
	public Float getSpeed() {
		return speed;
	}
	public void setSpeed(Float speed) {
		this.speed = speed;
	}
	public LatLng getPosition() {
		return position;
	}
	public void setPosition(LatLng position) {
		this.position = position;
	}
	public VehicleMessageCode getVehicleMessageCode() {
		return vehicleMessageCode;
	}
	public void setVehicleMessageCode(VehicleMessageCode vehicleMessageCode) {
		this.vehicleMessageCode = vehicleMessageCode;
	}
	public InetAddress getAddress() {
		return address;
	}
	public void setAddress(InetAddress address) {
		this.address = address;
	}
	public Integer getPort() {
		return port;
	}
	public void setPort(Integer port) {
		this.port = port;
	}
	public boolean isRemoveVehicle() {
		return removeVehicle;
	}
	public void setRemoveVehicle(boolean removeVehicle) {
		this.removeVehicle = removeVehicle;
	}
	public boolean isNewVehicle() {
		return newVehicle;
	}
	public void setNewVehicle(boolean newVehicle) {
		this.newVehicle = newVehicle;
	}

	public enum VehicleMessageCode
	{
		NOTIFY_INFO(2),
		SET_COMMAND(3);
		
		private final int code;
		private VehicleMessageCode(int code) {
			this.code = code;
		}
		
		public int getCode()
		{
			return this.code;
		}
		public static VehicleMessageCode fromCode(int vehicleMessageCode)
		{
			for(VehicleMessageCode vmc : VehicleMessageCode.values())
			{
				if(vmc.getCode()==vehicleMessageCode)
					return vmc;
			}
			throw new IllegalArgumentException("no VehicleMessageCode exists for the specified code");
		}
	}

}
